home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / emulator / bsvc-1.000 / bsvc-1 / bsvc-1.0.4 / src / Assemblers / hecasm / asm2.c < prev    next >
C/C++ Source or Header  |  1995-07-26  |  17KB  |  630 lines

  1. /* asm2.c assemble a line */
  2. /* this file contains the code to parse a line into its fields, 1 field */
  3. /* at a time.  There are two types of expressions permitted arithmetic */
  4. /* expressions and assembly expressions.  The format of arithmetic */
  5. /* expressions is "symbol = <expression>".  The format for assembly */
  6. /* expressions is "label:  opcode <modes> ;comment".  Arithmetic is */
  7. /* handled by a function called expr().  It will evaluate any arithmetic */
  8. /* expression still in the source buffer and report any errors. */
  9. /* The code to handle the addressing mode fields is all that need be written */
  10. /* by a user of this assembler */
  11. #include "asm.h"
  12.  
  13. /*
  14.  * Assemble a line.
  15.  */
  16. asmline()
  17. {
  18. static int mod, val, valid, shift, add, sh;
  19. register struct sym *sp;
  20. register struct sym *constant_label;
  21. int c;
  22. char id[NCPS];
  23.  
  24. struct d_operand     src,
  25.             dst,
  26.             getmode(),
  27.             getbmode();
  28. struct b_operand    cc,
  29.             getcc();
  30. int            comma_error;
  31.  
  32.  
  33.  
  34. /* these are default listing types.  dot->s_value is the value of the */
  35. /* location counter.  EMPTYLIS means there is no code generated on this */
  36. /* line.  This is only a default, if code is found the listmode will */
  37. /* be changed */
  38. listaddr = dot->s_value;
  39. listmode = EMPTYLIS;
  40.  
  41. /* No label defined yet:                        */
  42. constant_label = NULL;
  43.  
  44. loop:
  45. /* end of line or start of comment field */
  46. /* get a character from the source buffer */
  47. if((c=getnb())=='\0' || c==';')
  48.     return;
  49.  
  50. /* the first character of any statement must be an alphabetic */
  51. if(!alpha(c)) 
  52.     {
  53.     err('c',"illegal character");
  54.     return;
  55.     }
  56.  
  57. /* get a word from the source buffer and put it in id */
  58. getid(c, id);
  59.  
  60. /* get next character after word and decide what to do based on that */
  61. /*
  62.  * Direct assignment.
  63.  */
  64. if((c=getnb()) == '=') 
  65.     {
  66.     /* lookup name on left side of =. if it has already been defined */
  67.     /* and it is not the location counter then it is a multiply defined */
  68.     /* symbol */
  69.     sp = ustlookup(id);
  70.     if((sp->s_type & S_DEF) && (sp != dot))
  71.         err('m',"multiply defined symbol");
  72.  
  73.     /* evaluate the expression and put the value in the symbol pointed to */
  74.     /* by sp */
  75.     evaluate(sp);
  76.     listaddr = sp->s_value;
  77.  
  78.     /* if the expression contained unresolvable symbols it is not marked as */
  79.     /* defined.  If on the second pass it is still undefined then report */
  80.     /* an error */
  81.     if (pass != 0)
  82.         {
  83.         if (!(sp->s_type & S_DEF))
  84.             err('u',"undefined symbol");
  85.         /* this simple stands as a flag to tell where this symbol is defined */
  86.         sp->s_ref->r_stmtno = -sp->s_ref->r_stmtno;
  87.         }
  88.     else
  89.         sp->s_flag |= SF_ASG;
  90.  
  91.     /* another listing mode for expressions */
  92.     listmode = NOCODLIS;
  93.  
  94.     /* if this is not the end of the line then something is wrong */
  95.     if (((c = getnb()) != ';') && (c != '\0'))
  96.         err('x',"invalid expression");
  97.     }
  98. /*
  99.  * Label.
  100.  */
  101. else 
  102.     if(c == ':') 
  103.         {
  104.     /* lookup the label name */
  105.         if((sp=ustlookup(id)) == dot)
  106.             err('.',"illegal use of location counter");
  107.         else 
  108.             if(pass==0) 
  109.                 {
  110.         /* this checks to see if the label had previously been */
  111.         /* used as an arithmetic symbol */
  112.                 if((sp->s_type != S_UND) && ((sp->s_flag & SF_ASG)==0))
  113.                     sp->s_flag |= SF_MDF;
  114.                 sp->s_type |= S_VALID;
  115.                 sp->s_value = dot->s_value; 
  116.  
  117.         /* Could be constant definition:            */
  118.         /*    Save the pointer to the label:            */
  119.         constant_label = sp;
  120.                 }
  121.             else 
  122.                 {
  123.         /* same as for expressions */
  124.                 if(((sp->s_flag & SF_MDF) != 0) || (sp->s_flag & SF_ASG))
  125.                     err('m',"multiply defined symbol");
  126.                 sp->s_type |= S_DEF;
  127.                 sp->s_ref->r_stmtno = -sp->s_ref->r_stmtno;
  128.                 }
  129.     /* something has been found but no code generated yet. */
  130.     /* go back and parse out the next word */
  131.         listmode = NOCODLIS;
  132.         goto loop;
  133.         }
  134.     /*
  135.      * Normal (keyword) line.
  136.      */
  137.     else 
  138.         {
  139.     /* the line is not an assignment expression, and any labels have been
  140.         *  parsed out. There is still more text so it must be an opcode */
  141.         listmode = ALLLIS;
  142.  
  143.     /* convert the parsed word to all lower case */
  144.         lowerconv(id);
  145.         
  146.     /* put back the character that was taken out of the source buffer */
  147.         putback(c);
  148.  
  149.     /* look up the word in the permanent symbol table */
  150.         if((sp = pstlookup(id)) == NULL)
  151.             {
  152.             err('o',"illegal opcode");    /* Opcode not found in the pst */
  153.             return;
  154.             }
  155.         opcode = sp->s_value;
  156.  
  157.     /* all opcodes are assigned to groups so that ones with similar */
  158.     /* format can be handled identically */
  159.         switch(sp->s_type) 
  160.             {
  161. /* here is where the code must be inserted to decode the addressing modes, */
  162. /* fill in the opcode and output the correct result. "opcode" should */
  163. /* contain a constant portion of the actual opcode then additional */
  164. /* information gathered from the addressing modes should be ored into */
  165. /* base value and the output.  If any routines are used in decoding the */
  166. /* addressing modes they should be put in asm4.c.  The tools you have */
  167. /* in decoding the addressing modes are:*/
  168. /*    getnb()        : get a character from the source buffer */
  169. /*    getid(c,id)    : get next word, the first char was c */
  170. /*    expr()        : evaluate an expression an return its value */
  171. /*    ustlookup(id)    : lookup a word in the user symbol table */
  172. /*    pstlookup(id)    : lookup a word in the permanent symbol table */
  173. /*      comma()         : check next character to verify it is a comma */
  174. /* the code must be written to tie these together to decode a particular */
  175. /* set of addressing modes.  Any values that need to be output can */
  176. /* be placed in the output buffer by codew(value). */
  177.  
  178.  
  179. /* these are the pseudo operations provided by this assembler.  By looking */
  180. /* at them you can get an idea how to do the opcode part */
  181.             /* START PSEUDO OPERATIONS */
  182.             case GR_LIST:
  183.                 /* Turn listing on or off */
  184.                 if(!pass)
  185.                     break;
  186.                 if((c=getnb()) == '\0' || c == ';')
  187.                     break;
  188.  
  189.         /* get the word after the .list directive */
  190.                 getid(c,id);
  191.  
  192.         /* look it up in the permanent symbol table */
  193.         /* we are looking for "on" or "off" */
  194.                 if((sp = pstlookup(id)) == NULL)
  195.                     {
  196.                     err('u',"undefined symbol");
  197.                     break;
  198.                     }
  199.                 else 
  200.             /* check to see if it was one of the correct symbols */
  201.                     if(sp->s_type != GR_ONOFF)
  202.                         err('s',"improper symbol");
  203.  
  204.             /* give the listing flag its value */
  205.                     lflag = sp->s_value;
  206.                 break;
  207.  
  208.             case GR_ORG:
  209.                 /* Reset origin (program location) */
  210.         /* this can also be accomplished by .=<expression> */
  211.                 dot->s_value = expr();
  212.         listaddr = dot->s_value;
  213.                 break;
  214.  
  215.             case GR_BYTE:
  216.                 /* Define next byte in memory */
  217.                 do 
  218.                     {
  219.             /* get its value */
  220.                     codew(expr());
  221.                     } 
  222.                 while((c=getnb()) == ',');
  223.                 putback(c);
  224.                 break;
  225.  
  226.             case GR_WORD:
  227.                 /* Define next word in memory */
  228.                 do 
  229.                     {
  230.                     codew(expr());
  231.                     } 
  232.                 while((c=getnb()) == ',');
  233.                 putback(c);
  234.                 break;
  235.  
  236.             case GR_PASCII:
  237.                 /* Packed ascii string */
  238.                 ascii(0);
  239.                 break;
  240.  
  241.             case GR_UASCII:
  242.                 /* unpaced ascii string */
  243.                 ascii(1);
  244.                 break;
  245.  
  246.             case GR_RMW:
  247.                 /* Reserve  next x words in memory */    
  248.                 dot->s_value += expr();
  249.                 listmode = NOCODLIS;
  250.                 break;
  251.  
  252.             case GR_RMB:
  253.                 /* Reserve  next x bytes in memory */    
  254.                 dot->s_value += expr() * 2;
  255.                 listmode = NOCODLIS;
  256.                 break;
  257.  
  258.             case GR_RADIX:
  259.                 /* set radix */
  260.                 listmode = EMPTYLIS;
  261.                 radix = DEC;
  262.                 switch(expr())
  263.                    {
  264.                    case 2:
  265.                        radix = BIN;
  266.                        break;
  267.                    case 8:
  268.                        radix = OCT;
  269.                        break;
  270.                    case 10:
  271.                        radix = DEC;
  272.                        break;
  273.                    case 16:
  274.                        radix = HEX;
  275.                        break;
  276.                    default:
  277.                        err('n',"bad radix format");
  278.                        radix = OCT;
  279.                    }
  280.                 break;
  281.  
  282. /*----------------------------------------------------------------------
  283.    Constant definition:
  284. */
  285.  
  286.        case GR_EQU:        /* constant definition            */
  287.           if (pass==0)
  288.              if (constant_label==NULL)
  289.             err('l',"missing label");
  290.              else
  291.              {  constant_label->s_value = expr();
  292.             constant_label = NULL;
  293.              }
  294.           else
  295.           {  while (getnb()!='\0');
  296.          goto loop;
  297.           }
  298.           break;
  299.  
  300.  
  301. /*----------------------------------------------------------------------
  302.    Decode instructions:    
  303. */
  304.  
  305.         case GR_FMT1:    /* dual operand                */
  306.         src = getmode();
  307.         comma();
  308.         dst = getmode();
  309.  
  310.         /* Error occurred during parsing of operands:        */
  311.         if (src.parse_error || dst.parse_error)   
  312.            /* Do nothing:  skip all of the following        */
  313.            break;
  314.  
  315.         /* Can not have immediate mode in the destination:    */
  316.         if ((dst.mode==AM_IP) && (dst.reg==15))
  317.            err('#',"illegal destination addressing mode");
  318.  
  319.         /* Correct so far:  proceed with coding:        */
  320.         else
  321.         {  codew(opcode | (src.mode_bits<<10) | (dst.mode_bits<<8) |
  322.                   (src.reg<<4) | (dst.reg));
  323.  
  324.            /* Code extension word if src mode is 'immediate',
  325.              or indexed:                    */
  326.            if ((src.mode==AM_IP) && (src.reg==15)) /* immediate */
  327.               codew(src.ext_word);
  328.  
  329.            if (src.mode==AM_IX)
  330.               {
  331.               if (src.reg==15)    /* assemble as PC relative */
  332.                   codew(src.ext_word - dot->s_value - 1);
  333.               else
  334.                   codew(src.ext_word);
  335.               }
  336.            
  337.            /* Code extension word if dst mode is indexed:    */
  338.            if (dst.mode==AM_IX)
  339.               {
  340.               if (dst.reg==15)        /* PC Relative        */
  341.                  codew(dst.ext_word - dot->s_value);
  342.               else
  343.                  codew(dst.ext_word);
  344.               }
  345.         }
  346.         break;
  347.  
  348.  
  349.         case GR_FMT2:    /* single operand            */
  350.         src = getmode();
  351.  
  352.         /* Error occurred during parsing of operands:        */
  353.         if (src.parse_error)
  354.            /* Do nothing                    */
  355.            ;
  356.  
  357.         /* Can not have immediate mode:                */
  358.         else if ((src.mode==AM_IP) && (src.reg==15))
  359.            err('#',"illegal addressing mode");
  360.  
  361.         /* Correct so far:  proceed with coding:        */
  362.         else 
  363.         {  codew(opcode | (src.mode_bits<<10) |
  364.                   (src.reg<<4) | (src.reg));
  365.  
  366.            /* Code extension word if src mode is indexed:    */
  367.            if (src.mode==AM_IX)
  368.               if (src.reg==15)        /* PC Relative        */
  369.                  codew(src.ext_word - dot->s_value - 1);
  370.               else
  371.                  codew(src.ext_word);
  372.         }
  373.         break;
  374.  
  375.  
  376.         case GR_FMT3:    /* bra and jsr                */
  377.         comma_error = 0;
  378.         src = getbmode();
  379.         c = getnb();
  380.  
  381.         /* No comma, the "branch always" condition is implied:    */
  382.         if ((c==';') || (c=='\0'))
  383.         {  putback(c);
  384.            cc.parse_error = 0;
  385.            cc.mode_bits = 11;
  386.         }
  387.         else if (c==',')
  388.            cc = getcc();
  389.         else
  390.         {  err(',',"expecting comma");
  391.            comma_error = 1;
  392.         }
  393.  
  394.         /* Error occurred during parsing of operands:        */
  395.         if (src.parse_error || cc.parse_error || comma_error)
  396.            /* Do nothing                    */
  397.            ;
  398.  
  399.         /* Correct so far:  proceed with coding:        */
  400.         else 
  401.         {  codew(opcode | (src.mode_bits<<10) | (src.reg<<4) |
  402.                    (cc.mode_bits));
  403.             
  404.            /* Code extension word if branch mode is absolute,
  405.              relative, or indexed:                */
  406.            if ((src.mode==BM_A) || (src.mode==BM_I))
  407.               codew(src.ext_word);
  408.  
  409.            /* If relative, have to calc. offset:        */
  410.            else if (src.mode==BM_L)
  411.               codew(src.ext_word - dot->s_value - 1);
  412.         }
  413.         break;
  414.  
  415.  
  416.         case GR_FMT4:    /* no operand                */
  417.         codew(opcode);
  418.         break;
  419.  
  420.  
  421.         case GR_FMT5:    /* push                    */
  422.         src = getmode();
  423.         comma();
  424.         dst = getmode();
  425.  
  426.         /* Error occurred during parsing of operands:        */
  427.         if (src.parse_error || dst.parse_error)   
  428.            /* Do nothing                    */
  429.            ;
  430.  
  431.         /* Can only have 'register direct' in dst:        */
  432.         else if (dst.mode!=AM_RD) 
  433.            err('^',"illegal destination addressing mode");
  434.  
  435.         /* Correct so far:  proceed with coding:        */
  436.         else
  437.         {  codew(opcode | (src.mode_bits<<10) |
  438.                   (src.reg<<4) | (dst.reg));
  439.     
  440.            /* Code extension word if src mode is 'immediate',
  441.              'absolute', or indexed:            */
  442.            if (((src.mode==AM_IP) && (src.reg==15)) ||
  443.                (src.mode==AM_IX))
  444.  
  445.               /* PC Relative                    */
  446.               /* For PC relative, an offset is calc.:        */
  447.               if ((src.mode==AM_IX) && (src.reg==15))
  448.                  codew(src.ext_word - dot->s_value - 1);
  449.               else
  450.                  codew(src.ext_word);
  451.         }
  452.         break;
  453.  
  454.  
  455.         case GR_FMT6:    /* exch                    */
  456.         src = getmode();
  457.         comma();
  458.         dst = getmode();
  459.  
  460.         /* Error occurred during parsing of operands:        */
  461.         if (src.parse_error || dst.parse_error)   
  462.            /* Do nothing                    */
  463.            ;
  464.  
  465.         /* Can only have register direct:            */
  466.         else if ((src.mode!=AM_RD) || (dst.mode!=AM_RD))
  467.            err('D',"illegal addressing mode");
  468.  
  469.         /* Correct so far:  proceed with coding:        */
  470.         else
  471.            codew(opcode | (src.reg<<4) | (dst.reg));
  472.         break;
  473.  
  474.  
  475.         case GR_FMT7:    /* srch                    */
  476.         comma_error = 0;
  477.         src = getmode();
  478.         c = getnb();
  479.  
  480.         /* No comma, the "branch always" condition is implied:    */
  481.         if ((c==';') || (c=='\0'))
  482.         {  putback(c);
  483.            cc.parse_error = 0;
  484.            cc.mode_bits = 11;
  485.         }
  486.         else if (c==',')
  487.            cc = getcc();
  488.         else
  489.         {  err(',',"expecting comma");
  490.            comma_error = 1;
  491.         }
  492.  
  493.         /* Error occurred during parsing of operands:        */
  494.         if (src.parse_error || cc.parse_error || comma_error)
  495.            /* Do nothing                    */
  496.            ;
  497.  
  498.         /* Can only have register direct:            */
  499.         else if (src.mode!=AM_RD)
  500.            err('D',"illegal source addressing mode");
  501.  
  502.         /* Correct so far:  proceed with coding:        */
  503.         else
  504.            codew(opcode | (src.reg<<4) | (cc.mode_bits));
  505.         break;
  506.  
  507.         case GR_FMT8:    /* move                    */
  508.         src = getmode();
  509.         comma();
  510.         dst = getmode();
  511.  
  512.         /* Error occurred during parsing of operands:        */
  513.         if (src.parse_error || dst.parse_error)   
  514.            /* Do nothing:  skip all of the following        */
  515.            break;
  516.  
  517.         /* Can not have immediate mode in the destination:    */
  518.         if ((dst.mode==AM_IP) && (dst.reg==15))
  519.            err('#',"illegal destination addressing mode");
  520.  
  521.         /* Correct so far:  proceed with coding:        */
  522.         else
  523.         {  codew(opcode | (src.mode_bits<<10) | (dst.mode_bits<<8) |
  524.                   (src.reg<<4) | (dst.reg));
  525.  
  526.            /* Code extension word if src mode is 'immediate',
  527.              or indexed:                    */
  528.            if ((src.mode==AM_IP) && (src.reg==15)) /* immediate */
  529.               codew(src.ext_word);
  530.  
  531.            if (src.mode==AM_IX)
  532.               {
  533.               if (src.reg==15)    /* assemble as PC relative */
  534.               {
  535.               /* reg. dir. has different PC increment */
  536.               if (dst.mode == AM_RD)
  537.                       codew(src.ext_word - dot->s_value);
  538.               else
  539.                       codew(src.ext_word - dot->s_value - 1);
  540.               }
  541.               else
  542.                   codew(src.ext_word);
  543.               }
  544.            
  545.            /* Code extension word if dst mode is indexed:    */
  546.            if (dst.mode==AM_IX)
  547.               {
  548.               if (dst.reg==15)        /* PC Relative        */
  549.                  codew(dst.ext_word - dot->s_value - 1);
  550.               else
  551.                  codew(dst.ext_word);
  552.               }
  553.         }
  554.         break;
  555.  
  556.  
  557.         default:
  558.         err('u',"illegal instruction");
  559.  
  560.             } /* end switch */
  561.  
  562.     /* if there is yet more text then there is something that should not */
  563.     /* be there. */
  564.     if (((c = getnb()) != ';') && (c != '\0'))
  565.         err('X',"extra ignored");
  566.         
  567.         }
  568. }
  569.  
  570. /*
  571.  * Process the body of .pascii
  572.  * and .uascii pseudo ops.
  573.  * The z flag is true for a
  574.  * .uascii
  575.  */
  576. ascii(z)
  577. int z;
  578. {
  579. register int c, delim, n, last;
  580.  
  581. n = 0;
  582.  
  583. /* get the delimeter to be used this may be " or ' or / etc. */
  584. if((delim=getnb()) == '\0') 
  585.     {
  586.     err('q',"unexpected end of line");
  587.     return;
  588.     }
  589.  
  590. if(!(z))
  591.     {
  592.     while((c=getmap()) != '\0' && c != delim)
  593.         {
  594.         if(++n >= 2)
  595.             {
  596.             codew(last * 256 + c);
  597.             n = 0;
  598.             }
  599.         last = c;
  600.         }
  601.     
  602.     if(n == 1)
  603.         codew(last * 256);
  604.     else
  605.         codew(0);
  606.  
  607.     if(c == '\0')
  608.         err('q',"unexpected end of line");
  609.     }
  610. else
  611.     {
  612.     while((c=getmap()) != '\0' && c != delim)
  613.         codew(c);
  614.     codew(0);
  615.  
  616.     if(c == '\0')
  617.         err('q',"unexpected end of line");
  618.     }
  619. }
  620.  
  621. /*
  622.  * Check for `,'.
  623.  */
  624. comma()
  625. {
  626.  
  627. if(getnb() != ',')
  628.     err(',',"missing comma");
  629. }
  630.